﻿(function ($) {

    var methods = {
        init: function () {
            var t = $(this), args = arguments;

            // Check whether we have already created a select element
            var wrapper = this.data('select');
            if (wrapper && wrapper.length !== 0)
                return this;

            // Setup the selection wrapper 
            var list = $('<ul class="ui-select-items"></ul>');
            list.delegate('li', 'click', changeSelected);

            // Setup the containing div
            var wrapper = $('<div class="ui-element ui-select "></div>');
            wrapper.append('<div class="ui-select-selected">&nbsp;</div>');
            wrapper.append('<button>*</button>');
            wrapper.append('<div class="ui-select-inner"></div>');

            // Use visibility to enable measuring width,
            // yet make sure the user isn't bothered with unnecessary rendering
            wrapper.find('div.ui-select-inner').css('visibility', 'hidden');
            wrapper.find('div.ui-select-inner').append(list);

            // Enable the drop button to display the options
            wrapper.find('button').button(function (e) {
                wrapper.find('div.ui-select-inner').show();
                e.stopPropagation();
            });
            // Enable hiding the options if something unknown was clicked
            $(document).click(hide);

            // Insert the dummy select into DOM, after the original element
            t.hide();
            t.after(wrapper);

            var active = wrapper.find('div.ui-select-selected'), selected = null;
            var maxW = 0;

            // Setup the options and set the length according to the longest option
            t.find('option').each(function (i, option) {
                option = $(option);

                var li = $('<li _ui_value="' + option.attr('value') + '">' +
                    option.text() + '</li>');
                list.append(li);

                // Set option text to active and check it's width
                active.text(option.text());
                if (maxW < active.width())
                    maxW = active.width();

                // In case a default value was specified in DOM
                if (typeof option.attr('selected') !== 'undefined')
                    selected = li;
            });

            // Set the element's max width according to largest option
            active.width(maxW);

            // Set the active value visible
            if (selected !== null)
                active.text(selected.text());
            else
                active.text(list.find('li:first').text());

            hide();
            // Done with probing, no need to hide any more
            wrapper.find('div.ui-select-inner').css('visibility', 'visible');
            t.data('select', wrapper);

            function changeSelected(e) {
                e.stopPropagation();
                active.text($(this).text());
                if (args.length !== 0) {
                    args[0]($(this).attr('_ui_value'));
                }
                hide();
            }

            function hide() {
                wrapper.find('div.ui-select-inner').hide();
            }

            return this;
        },

        enable: function () {
            var t = $(this), wrapper = t.data('select');
            wrapper.removeClass('ui-select-disabled');
            wrapper.addClass('ui-select-enabled');
            wrapper.find('button').button('enable');
            t.removeAttr('disabled');
        },

        disable: function () {
            var t = $(this), wrapper = t.data('select');
            wrapper.removeClass('ui-select-enabled');
            wrapper.addClass('ui-select-disabled');
            wrapper.find('button').button('disable');
            t.attr('disabled', 'disabled');
        },

        destroy: function () { }
    };

    $.fn.select = function (method) {
        // Choose the correct action
        if (methods[method]) {
            return methods[method].apply(this, arguments);
        } else if (typeof method === 'object' || typeof method === 'function'
                || !method) {
            return methods.init.apply(this, arguments);
        }
    }

})(jQuery);